package com.mutouren.common.config;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.mutouren.common.exception.ExceptionUtils;
import com.mutouren.common.utils.ClassLoaderUtils;

public class ConfigManager {

	private static final String configFilePath = "mutouren.xml";
	private static volatile Document configDocument;
	private static final String DEFAULT_DATEPATTERN = "yyyy-MM-dd";
	private static final String DEFAULT_ATTRIBUTENAME = "value";
	
	private static Lock lock = new ReentrantLock();
//	private static Logger errorLogger = LogManager.getLogger("SystemErrorLog");
//	private static Logger runLogger = LogManager.getLogger("SystemRunLog");
	
	private static void loadConfig() {		
		try {
			SAXReader saxReader = new SAXReader();	
			configDocument = saxReader.read(ClassLoaderUtils.getResourceAsURL(configFilePath));
			
			//runLogger.info(String.format("system already loaded %s", configFilePath));
		} catch (Throwable t) {
			// log
			//errorLogger.error("loading config mutouren.xml error!", t);
			throw new RuntimeException("loading config mutouren.xml error!", t);
		}
	}
	
	private static Document getXmlConfig() {
		Document config = configDocument;		
		if(config == null) {
			lock.lock();
			try {
				config = configDocument;
				if(config == null) {
					loadConfig();
					config = configDocument;
				}				
			} catch (Throwable t) {
				throw ExceptionUtils.doUnChecked(t);
			} finally {
				lock.unlock();
			}			
		}
			
		return config;
	}

	/**
	 * @param nodeName
	 * @return
	 */
	private static String getNodePath(String nodeName) {
		return String.format("/configuration/%s", nodeName);
	}

	/**
	 * @param nodeName
	 * @return
	 */
	public static Element getElement(String nodeName) {
		Element e = (Element) getXmlConfig().selectSingleNode(getNodePath(nodeName));
		if(e == null) throw new RuntimeException(String.format("config node: '%s' no exist.", nodeName));
		return e;
	}

	/**
	 * @param nodeName
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static List<Element> getElements(String nodeName) {
		List list = getXmlConfig().selectNodes(getNodePath(nodeName));
		return (List<Element>) list;
	}

	/**
	 * @param nodeName
	 * @return
	 */
	public static boolean getBoolValue(String nodeName) {		
		return Boolean.parseBoolean(getStringValue(nodeName));
	}
	/**
	 * @param nodeName
	 * @param attributeName
	 * @return
	 */
	public static boolean getBoolValue(String nodeName, String attributeName) {		
		return Boolean.parseBoolean(getStringValue(nodeName, attributeName));
	}	
	/**
	 * @param nodeName
	 * @return
	 */
	public static int getIntValue(String nodeName) {
		return Integer.parseInt(getStringValue(nodeName));
	}
	/**
	 * @param nodeName
	 * @param attributeName
	 * @return
	 */
	public static int getIntValue(String nodeName, String attributeName) {
		return Integer.parseInt(getStringValue(nodeName, attributeName));
	}
	
	/**
	 * @param nodeName
	 * @return
	 */
	public static long getLongValue(String nodeName) {
		return Long.parseLong(getStringValue(nodeName));
	}
	/**
	 * @param nodeName
	 * @param attributeName
	 * @return
	 */
	public static long getLongValue(String nodeName, String attributeName) {
		return Long.parseLong(getStringValue(nodeName, attributeName));
	}
	
	/**
	 * @param nodeName
	 * @return
	 */
	public static BigDecimal getBigDecimalValue(String nodeName) {
		return new BigDecimal(getStringValue(nodeName));
	}
	/**
	 * @param nodeName
	 * @param attributeName
	 * @return
	 */
	public static BigDecimal getBigDecimalValue(String nodeName, String attributeName) {
		return new BigDecimal(getStringValue(nodeName, attributeName));
	}		
	/**
	 * @param nodeName
	 * @return
	 */
	public static Date getDateValue(String nodeName) {
		return getDateValue(nodeName, DEFAULT_ATTRIBUTENAME, DEFAULT_DATEPATTERN);
	}
	/**
	 * @param nodeName
	 * @param attributeName
	 * @param datePattern
	 * @return
	 */
	public static Date getDateValue(String nodeName, String attributeName, String datePattern) {
		try {		
			return new SimpleDateFormat(datePattern).parse(getStringValue(nodeName, attributeName));
		} catch (ParseException e) {
			throw ExceptionUtils.doUnChecked(e);
		}
	}				
	/**
	 * @param nodeName 已加路径 "/configuration"
	 * @return
	 * 
	 * 提示: 默认attributeName="value"
	 */
	public static String getStringValue(String nodeName) {
		return getStringValue(nodeName, DEFAULT_ATTRIBUTENAME);
	}
	
	/**
	 * @param nodeName 已加路径 "/configuration"
	 * @param attributeName
	 * @return
	 */
	public static String getStringValue(String nodeName, String attributeName) {
		return getElement(nodeName).attribute(attributeName).getValue();
	}	

	static {
		// init
	}
}

